using System;
using System.IO;
using System.Collections;

namespace Dokan
{
    public class DokanFileInfo
    {
        public Object Context;
        public bool IsDirectory;
        public ulong InfoId;
        public uint ProcessId;
        public bool DeleteOnClose;
        public bool PagingIo;
        public bool SynchronousIo;
        public bool Nocache;
        public bool WriteToEndOfFile;
        public readonly ulong DokanContext; // for internal use

        public DokanFileInfo(ulong dokanContext)
        {
            Context = null;
            IsDirectory = false;
            DeleteOnClose = false;
            PagingIo = false;
            SynchronousIo = false;
            Nocache = false;
            WriteToEndOfFile = false;
            InfoId = 0;
            DokanContext = dokanContext;
        }
    }


    public class FileInformation
    {
        public FileAttributes Attributes;
        public DateTime CreationTime;
        public DateTime LastAccessTime;
        public DateTime LastWriteTime;
        public long Length;
        public string FileName;
        /*
        public FileInformation()
        {
            Attributes = FileAttributes.Normal;
            Length = 0;
        }
         */
    }

    /// <summary>
    /// To implement a Dokan filesystem, one must implement this interface.
    /// </summary>
    public interface DokanOperations
    {
        /// <summary>
        /// Creates or opens a file or I/O device.
        /// </summary>
        ///<remarks>
        /// http://127.0.0.1:47873/help/1-5816/ms.help?method=page&id=80A96083-4DE9-4422-9705-B8AD2B6CBD1B&product=VS&productversion=100&locale=en-US&format=html&topicVersion=85&topicLocale=EN-US&embedded=true
        /// 
        /// Creates or opens a file or I/O device. The most commonly used I/O
        /// devices are as follows: file, file stream, directory, physical
        /// disk, volume, console buffer, tape drive, communications resource,
        /// mailslot, and pipe.
        /// </remarks>
        /// <param name="filename">The name of the file or device to be created or opened.</param>
        /// <param name="access"><see cref="System.IO.FileAccess"/></param>
        /// <param name="share"><see cref="System.IO.FileShare"/></param>
        /// <param name="mode"><see cref="System.IO.FileMode"/></param>
        /// <param name="options"><see cref="System.IO.FileOptions"/></param>
        /// <param name="info"><see cref="DokanFileInfo"/></param>
        /// <returns>A Windows error code, or 0 on no error.</returns>
        int CreateFile(
                string filename,
                FileAccess access,
                FileShare share,
                FileMode mode,
                FileOptions options,
                DokanFileInfo info);

        /// <summary>
        /// Opens a directory.
        /// </summary>
        /// <param name="filename">The directory name passed.</param>
        /// <param name="info">The DokanFileInfo for this directory.</param>
        /// <returns>a Windows error code, or 0 on no error.</returns>
        int OpenDirectory(
                string filename,
                DokanFileInfo info);

        /// <summary>
        /// Creates a new directory.
        /// </summary>
        /// <param name="filename">The new directory's name.</param>
        /// <param name="info">The DokanFileInfo for this request.</param>
        /// <returns>a Windows error code, or 0 on no error.</returns>
        int CreateDirectory(
                string filename,
                DokanFileInfo info);
        /// <summary>
        /// Called by Dokan when a file is closed.
        /// </summary>
        /// <param name="filename">The name of the file that was closed.</param>
        /// <param name="info">The DokanFileInfo describing the file.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int Cleanup(
                string filename,
                DokanFileInfo info);

        /// <summary>
        /// Called after Cleanup().
        /// </summary>
        /// <param name="filename">The filename which is being closed.</param>
        /// <param name="info">The DokanFileInfo describing the file.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int CloseFile(
                string filename,
                DokanFileInfo info);
        
        /// <summary>
        /// Reads bytes from a file.
        /// </summary>
        /// <param name="filename">The name of the file to read from.</param>
        /// <param name="buffer">The buffer to read into.</param>
        /// <param name="readBytes">The number of bytes [i]to read/[o]actually read.</param>
        /// <param name="offset">The offset into the file to begin reading from.</param>
        /// <param name="info">The DokanFileInfo describing the file.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int ReadFile(
                string filename,
                byte[] buffer,
                ref uint readBytes,
                long offset,
                DokanFileInfo info);

        /// <summary>
        /// Writes bytes to a file, starting at a given logical position.
        /// </summary>
        /// <param name="filename">The name of the file to write to.</param>
        /// <param name="buffer">The buffer containing the data to write.</param>
        /// <param name="writtenBytes">The number of bytes [i] to write/[o]actually written.</param>
        /// <param name="offset">The logical position to begin writing the buffer.</param>
        /// <param name="info">The DokanFileInfo describing this file.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int WriteFile(
                string filename,
                byte[] buffer,
                ref uint writtenBytes,
                long offset,
                DokanFileInfo info);

        /// <summary>
        /// Causes any changed but unwritten data to be written to disk.
        /// </summary>
        /// <param name="filename">The name of the file to flush.</param>
        /// <param name="info">The DokanFileInfo describing this file.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int FlushFileBuffers(
                string filename,
                DokanFileInfo info);

        /// <summary>
        /// Obtain filesystem information about the given file.
        /// </summary>
        /// <param name="filename">The name of the file to query.</param>
        /// <param name="fileinfo">The FileInformation structure to populate.</param>
        /// <param name="info">The DokanFileInfo describing this file.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int GetFileInformation(
                string filename,
                FileInformation fileinfo,
                DokanFileInfo info);

        /// <summary>
        /// Gets a list of files matching a given pattern.
        /// </summary>
        /// <param name="filename">The name of the file to query.</param>
        /// <param name="files">The list of DokanFileInfo objects to populate.</param>
        /// <param name="info">The DokanFileInfo with the context to query.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int FindFiles(
                string filename,
                ArrayList/*<DokanFileInfo>*/ files,
                DokanFileInfo info);

        /// <summary>
        /// Sets the filesystem attributes of the given file.
        /// </summary>
        /// <param name="filename">The name of the file which attributes to alter.</param>
        /// <param name="attr">The file's new attributes.</param>
        /// <param name="info">The DokanFileInfo which context the file exists within.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int SetFileAttributes(
                string filename,
                FileAttributes attr,
                DokanFileInfo info);

        /// <summary>
        /// Sets the file's creation, access, and modification times.
        /// </summary>
        /// <param name="filename">The filename to work on.</param>
        /// <param name="ctime">The file's new creation time.</param>
        /// <param name="atime">The file's new access time.</param>
        /// <param name="mtime">The file's new modification time.</param>
        /// <param name="info">The DokanFileInfo with the context to work in.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int SetFileTime(
                string filename,
                DateTime ctime,
                DateTime atime,
                DateTime mtime,
                DokanFileInfo info);

        /// <summary>
        /// Deletes a file.
        /// </summary>
        /// <param name="filename">The name of the file to delete.</param>
        /// <param name="info">The context within which to delete.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int DeleteFile(
                string filename,
                DokanFileInfo info);

        /// <summary>
        /// Removes a directory.  The directory must be empty.
        /// </summary>
        /// <param name="filename">The name of the directory to delete.</param>
        /// <param name="info">The context to remove the directory from.</param>
        /// <returns></returns>
        int DeleteDirectory(
                string filename,
                DokanFileInfo info);

        /// <summary>
        /// Renames a file.
        /// </summary>
        /// <param name="filename">The name of the file to change the name of.</param>
        /// <param name="newname">The new name of the file.</param>
        /// <param name="replace">If newname already exists, should this overwrite?</param>
        /// <param name="info">The context within which to work.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int MoveFile(
                string filename,
                string newname,
                bool replace,
                DokanFileInfo info);

        /// <summary>
        /// Sets the length of a file, either extending or truncating it.
        /// </summary>
        /// <remarks>If this is used to extend a file, the file becomes sparse.</remarks>
        /// <param name="filename">The name of the file to set the length of.</param>
        /// <param name="length">The new length of the file.</param>
        /// <param name="info">The context against which to match the filename.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int SetEndOfFile(
                string filename,
                long length,
                DokanFileInfo info);

        /// <summary>
        /// Alters the actual allocation for the file.
        /// </summary>
        /// <param name="filename">The name of the file to allocate.</param>
        /// <param name="length">The new length of the allocation.</param>
        /// <param name="info">The context within which filename exists.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int SetAllocationSize(
                string filename,
                long length,
                DokanFileInfo info);

        /// <summary>
        /// Locks a specified range in the file.
        /// </summary>
        /// <param name="filename">The name of the file to lock some portion of.</param>
        /// <param name="offset">The beginning offset of the region to lock.</param>
        /// <param name="length">The length of the region to lock.</param>
        /// <param name="info">The context within which to work.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int LockFile(
                string filename,
                long offset,
                long length,
                DokanFileInfo info);

        /// <summary>
        /// Unlocks the specified range in the file.
        /// </summary>
        /// <param name="filename">The name of the file to unlock some portion of.</param>
        /// <param name="offset">The beginning offset of the region to unlock.</param>
        /// <param name="length">The length of the region to unlock.</param>
        /// <param name="info">The context within which to work.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int UnlockFile(
                string filename,
                long offset,
                long length,
                DokanFileInfo info);

        /// <summary>
        /// Gets the free space on the volume.
        /// </summary>
        /// <param name="freeBytesAvailable">out: The maximum allocation of a file just created.</param>
        /// <param name="totalBytes">out: The total usable size of the volume.</param>
        /// <param name="totalFreeBytes">out: The total free byte count.</param>
        /// <param name="info">The context to query</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int GetDiskFreeSpace(
                ref ulong freeBytesAvailable,
                ref ulong totalBytes,
                ref ulong totalFreeBytes,
                DokanFileInfo info);

        /// <summary>
        /// Unmounts the filesystem.
        /// </summary>
        /// <param name="info">The DokanContext to unmount.</param>
        /// <returns>A Windows error code, or 0 on success.</returns>
        int Unmount(
                DokanFileInfo info);

    }
}
